package com.cq.hd.product.validator;

import com.cq.hd.common.constant.Constant;
import com.cq.hd.common.enums.biz.*;
import com.cq.hd.common.response.Throw;
import com.cq.hd.common.utils.LocalDateUtil;
import com.cq.hd.product.api.dto.*;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 活动校验类 for 报名
 *
 * @author much
 * @since 2024/05/17 20:52
 */
@Component
public class ActiveEnrollValidator extends ActivePublishValidator {

    @Override
    Boolean match(ActiveReleaseDto activeReleaseDto) {
        return activeReleaseDto.getActiveType().equals(ActiveTypeEnum.ENROLL.getValue())
                || activeReleaseDto.getActiveType().equals(ActiveTypeEnum.GROUP_ENROLL.getValue());
    }

    public void doValidate(ActiveReleaseDto activeReleaseDto) {
        // 校验活动有效时间
        validateUseTime(activeReleaseDto);
        // 阶梯价状态
        validateStepPriceSate(activeReleaseDto);
        // 阶梯价设置
        validateStepPrice(activeReleaseDto);
        // 报名人数
        validateEnrollSetting(activeReleaseDto);
        // 阶梯价差价校验
        validateStepPriceDiff(activeReleaseDto);
        // 核销方式
        validateVerifyMethod(activeReleaseDto);
        // 报名信息项
        validateEnrollItems(activeReleaseDto);
        // 是否需要签到
        validateSignInRequired(activeReleaseDto);
    }

    // 纯报名活动需要开启签到
    private void validateSignInRequired(ActiveReleaseDto activeReleaseDto) {
        if (!activeReleaseDto.getActiveType().equals(ActiveTypeEnum.ENROLL.getValue())) {
            return;
        }
        if (activeReleaseDto.getSignInRequired().equals(0)) {
            Throw.isBusinessException("报名活动必须开启签到");
        }
    }

    // 校验活动有效时间
    private void validateUseTime(ActiveReleaseDto activeReleaseDto) {
        // 没有设置满员自动退，不需校验
        if (NoFullAutoRefundStateEnum.NO.getValue().equals(activeReleaseDto.getNoFullAutoRefundState())) {
            return;
        }

        LocalDateTime endLocalDateTime = null;
        try {
            endLocalDateTime = LocalDateUtil.toLocalDateTime(activeReleaseDto.getEndTime(), Constant.YYYY_MM_DD_HH_MM_SS);
        } catch (Exception e) {
            Throw.isBusinessException("活动时间设置有误");
        }


        LocalDateTime validStartLocalDateTime = null;
        try {
            validStartLocalDateTime = LocalDateUtil.toLocalDateTime(activeReleaseDto.getValidStartTime(), Constant.YYYY_MM_DD_HH_MM_SS);
        } catch (Exception e) {
            Throw.isBusinessException("使用时间设置有误");
        }

        // 没有开启未满员自动退的报名活动，有效时间是可以和起止时间同步的，只有开启了未满员自动退，才需要限制
        if (endLocalDateTime.isAfter(validStartLocalDateTime)) {
            Throw.isBusinessException("活动结束时间不能晚于活动有效开始时间");
        }
    }

    // 阶梯价格状态
    private void validateStepPriceSate(ActiveReleaseDto activeReleaseDto) {
        // 是否是阶梯价格(1-否，2-是)
        Integer stepPriceState = activeReleaseDto.getStepPriceState();
        if (stepPriceState == null || StepPriceStateEnum.typeOf(stepPriceState) == null) {
            Throw.isBusinessException("请设置阶梯价格状态");
        }
        // 拼团 & 报名开启，不允许设置阶梯价
        if (PromotionTypeEnum.GROUP_BUY.name().equals(activeReleaseDto.getPromotionType())
                && stepPriceState.equals(StepPriceStateEnum.YES.getValue())) {
            Throw.isBusinessException("拼团活动不允许设置阶梯价");
        }
    }

//    private void validateCommissionAmt(ActiveReleaseDto activeReleaseDto) {
//        if (!AgentStateEnum.OPEN.getValue().equals(activeReleaseDto.getActiveState())
//                || !DefaultCommissionTypeEnum.COMMISSION.getValue().equals(activeReleaseDto.getDefaultCommissionType())) {
//            return;
//        }
//        // 获取阶梯最小价格
//        List<ActiveStepPriceSonDto> activeStepPriceSonDtos = activeReleaseDto.getActiveStepPrices().stream()
//                .sorted(Comparator.comparing(ActiveStepPriceSonDto::getEnrollPrice).reversed())
//                .collect(Collectors.toList());
//        ActiveStepPriceSonDto activeStepPriceSon = activeStepPriceSonDtos.get(0);
//        BigDecimal minActivePrice = activeStepPriceSon.getEnrollPrice();
//        BigDecimal commissionAmt = activeReleaseDto.getCommissionAmt();
//
//        // 固定佣金不能大于等于活动价格
//        // 如果是阶梯价格，固定佣金不能大于等于阶梯最小价格
//        if (StepPriceStateEnum.YES.getValue().equals(activeReleaseDto.getStepPriceState())) {
//            if (commissionAmt.compareTo(minActivePrice) >= 0) {
//                Throw.isBusinessException("固定金额不能大于等于活动阶梯最小价格");
//            }
//        } else {
//            if (commissionAmt.compareTo(activeReleaseDto.getActivePrice()) >= 0) {
//                Throw.isBusinessException("固定金额不能大于等于活动价格");
//            }
//        }
//    }

    // 校验阶梯价配置
    private void validateStepPrice(ActiveReleaseDto activeReleaseDto) {
        BigDecimal minActivePrice = BigDecimal.ZERO;
        List<ActiveStepPriceSonDto> activeStepPrices = activeReleaseDto.getActiveStepPrices();
        if (StepPriceStateEnum.YES.getValue().equals(activeReleaseDto.getStepPriceState())) {
            if (ZeroStateEnum.YES.getValue().equals(activeReleaseDto.getZeroState())) {
                Throw.isBusinessException("零元购活动不能设置阶梯价格");
            }

            if (org.springframework.util.CollectionUtils.isEmpty(activeStepPrices)) {
                Throw.isBusinessException("请设置阶梯价格");
            }

            if (activeStepPrices.size() > 3) {
                Throw.isBusinessException("最多支持3个阶梯价格");
            }

            if (activeStepPrices.size() < 2) {
                Throw.isBusinessException("最少支持2个阶梯价格");
            }

            Map<Integer, ActiveStepPriceSonDto> enrollNumMap = new HashMap<>();
            Map<BigDecimal, ActiveStepPriceSonDto> enrollPriceMap = new HashMap<>();

            // 校验阶梯报名人数和价格
            for (ActiveStepPriceSonDto activeStepPrice : activeStepPrices) {
                Integer getEnrollNum = activeStepPrice.getEnrollNum();
                BigDecimal getEnrollPrice = activeStepPrice.getEnrollPrice();

                if (getEnrollNum <= 0) {
                    Throw.isBusinessException("阶梯报名人数必须大于0个");
                }

                if (getEnrollPrice.compareTo(BigDecimal.ZERO) <= 0) {
                    Throw.isBusinessException("阶梯报名价格必须大于0元");
                }

                if (enrollNumMap.containsKey(getEnrollNum)) {
                    Throw.isBusinessException("阶梯报名人数不能相同");
                }
                enrollNumMap.put(getEnrollNum, activeStepPrice);

                if (enrollPriceMap.containsKey(getEnrollPrice)) {
                    Throw.isBusinessException("阶梯报名金额不能相同");
                }

                enrollPriceMap.put(getEnrollPrice, activeStepPrice);
            }

            // 根据报名人数升序
            List<ActiveStepPriceSonDto> activeStepPriceSons = activeStepPrices.stream()
                    .sorted(Comparator.comparing(ActiveStepPriceSonDto::getEnrollNum))
                    .collect(Collectors.toList());
            // 第一阶梯
            ActiveStepPriceSonDto firstActiveStepPriceSonDto = activeStepPriceSons.get(0);
            Integer firstEnrollNum = firstActiveStepPriceSonDto.getEnrollNum();
            BigDecimal firstEnrollPrice = firstActiveStepPriceSonDto.getEnrollPrice();

            // 第二阶梯
            ActiveStepPriceSonDto secondActiveStepPriceSonDto = activeStepPriceSons.get(1);
            Integer secondEnrollNum = secondActiveStepPriceSonDto.getEnrollNum();
            BigDecimal secondEnrollPrice = secondActiveStepPriceSonDto.getEnrollPrice();

            // 限制第一阶梯人数必须小于第二阶梯，第一阶梯价格必须大于第二阶梯
            if (firstEnrollNum >= secondEnrollNum) {
                Throw.isBusinessException("阶梯二人数需大于阶梯一人数");
            }

            if (firstEnrollPrice.compareTo(secondEnrollPrice) <= 0) {
                Throw.isBusinessException("阶梯二价格需低于阶梯一价格");
            }

            // 第三阶梯
            if (activeStepPriceSons.size() > 2) {
                ActiveStepPriceSonDto threeActiveStepPriceSonDto = activeStepPriceSons.get(2);
                Integer threeEnrollNum = threeActiveStepPriceSonDto.getEnrollNum();
                BigDecimal threeEnrollPrice = threeActiveStepPriceSonDto.getEnrollPrice();

                // 限制第二阶梯人数必须小于第三阶梯，第二阶梯价格必须大于第三阶梯
                if (secondEnrollNum >= threeEnrollNum) {
                    Throw.isBusinessException("阶梯三人数需大于阶梯二人数");
                }

                if (secondEnrollPrice.compareTo(threeEnrollPrice) <= 0) {
                    Throw.isBusinessException("阶梯三价格需低于阶梯二价格");
                }
            }

//            // 以阶梯价格配置的最少人数所对应的价格去计算佣金，而不是最大的价格，去计算佣金比例 TODO
//            activePrice = firstEnrollPrice;

            // 获取阶梯最小价格
            List<ActiveStepPriceSonDto> activeStepPriceSonDtos = activeStepPrices.stream()
                    .sorted(Comparator.comparing(ActiveStepPriceSonDto::getEnrollPrice).reversed())
                    .collect(Collectors.toList());
            ActiveStepPriceSonDto activeStepPriceSon = activeStepPriceSonDtos.get(0);
            minActivePrice = activeStepPriceSon.getEnrollPrice();

//            // 获取阶梯最大人数 TODO
//            enrollNum = activeStepPriceSons.get(activeStepPriceSons.size() - 1).getEnrollNum();
        }
    }

    private void validateStepPriceDiff(ActiveReleaseDto activeReleaseDto) {
        // 限制 阶梯间差价须≤（阶梯 1 价格-红包-佣金）
        if (StepPriceStateEnum.YES.getValue().equals(activeReleaseDto.getStepPriceState())) {
            // 根据报名人数升序
            List<ActiveStepPriceSonDto> activeStepPriceSons = activeReleaseDto.getActiveStepPrices().stream()
                    .sorted(Comparator.comparing(ActiveStepPriceSonDto::getEnrollNum))
                    .collect(Collectors.toList());
            // 第一阶梯
            ActiveStepPriceSonDto firstActiveStepPriceSonDto = activeStepPriceSons.get(0);
            BigDecimal firstEnrollPrice = firstActiveStepPriceSonDto.getEnrollPrice();

            // 第二阶梯
            ActiveStepPriceSonDto secondActiveStepPriceSonDto = activeStepPriceSons.get(1);
            BigDecimal secondEnrollPrice = secondActiveStepPriceSonDto.getEnrollPrice();

            // 阶梯间差价须≤（阶梯 1 价格-红包-佣金）
            BigDecimal diffAmt = firstEnrollPrice.subtract(secondEnrollPrice);
            BigDecimal firstRedPacketAmt = Optional.ofNullable(activeReleaseDto.getActiveRedPacket())
                    .map(ActiveRedPacketSonDto::getFirstRedPacketAmt).orElse(BigDecimal.ZERO);

            BigDecimal actualCommissionAmt = activeReleaseDto.getActivePrice()
                    .multiply(activeReleaseDto.getCommissionRate()).divide(new BigDecimal("100"), 2, RoundingMode.DOWN);
            BigDecimal tmpSubAmt = firstEnrollPrice.subtract(firstRedPacketAmt).subtract(actualCommissionAmt);
            if(diffAmt.compareTo(tmpSubAmt) > 0){
                Throw.isBusinessException("阶梯间差价须≤(阶梯1价格-红包-佣金)");
            }

            // 第三阶梯
            if (activeStepPriceSons.size() > 2) {
                ActiveStepPriceSonDto threeActiveStepPriceSonDto = activeStepPriceSons.get(2);
                BigDecimal threeEnrollPrice = threeActiveStepPriceSonDto.getEnrollPrice();

                // 阶梯间差价须≤（阶梯 1 价格-红包-佣金）
                diffAmt = firstEnrollPrice.subtract(threeEnrollPrice);
                if(diffAmt.compareTo(tmpSubAmt) > 0){
                    Throw.isBusinessException("阶梯间差价须≤(阶梯1价格-红包-佣金)");
                }
            }
        }
    }

    // 报名人数必填
    private void validateEnrollSetting(ActiveReleaseDto activeReleaseDto) {
        Integer enrollNum = getEnrollNum(activeReleaseDto);
        // 拼团不用校验报名人数
        if (activeReleaseDto.getPromotionType() == null) {
            if (enrollNum == null || enrollNum <= 0) {
                Throw.isBusinessException("报名人数必须大于0个");
            }
            if (enrollNum > 99999999) {
                Throw.isBusinessException("报名人数不能超过99999999个");
            }
        }
        // 报名次数限制必填
        Integer limitEnrollNum = activeReleaseDto.getLimitEnrollNum();
        if (limitEnrollNum == null) {
            activeReleaseDto.setLimitEnrollNum(activeReleaseDto.getLimitBuyNum());
        }
//        if (limitEnrollNum == null || limitEnrollNum <= 0) {
//            Throw.isBusinessException("报名次数限制必须大于0个");
//        }
    }

    private Integer getEnrollNum(ActiveReleaseDto activeReleaseDto) {
        if (StepPriceStateEnum.YES.getValue().equals(activeReleaseDto.getStepPriceState())) {
            List<ActiveStepPriceSonDto> activeStepPrices = activeReleaseDto.getActiveStepPrices();
            // 根据报名人数升序
            List<ActiveStepPriceSonDto> activeStepPriceSons = activeStepPrices.stream()
                    .sorted(Comparator.comparing(ActiveStepPriceSonDto::getEnrollNum))
                    .collect(Collectors.toList());
            return activeStepPriceSons.get(activeStepPriceSons.size() - 1).getEnrollNum();
        } else {
            return activeReleaseDto.getEnrollNum();
        }
    }

    // 核销方式必填
    private void validateVerifyMethod(ActiveReleaseDto activeReleaseDto) {
        Integer verifyMethod = activeReleaseDto.getVerifyMethod();
        if (verifyMethod == null || VerifyMethodEnum.typeOf(verifyMethod) == null) {
            Throw.isBusinessException("请设置核销方式");
        }
    }

    // 报名信息必填，最多添加6个，单选内容最少2个，最多10个
    private void validateEnrollItems(ActiveReleaseDto activeReleaseDto) {
        List<ActiveEnrollInfoSonDto> activeEnrollInfos = activeReleaseDto.getActiveEnrollInfos();
        if (CollectionUtils.isEmpty(activeEnrollInfos)) {
            return;
        }

        if (activeEnrollInfos.size() > 10) {
            Throw.isBusinessException("报名信息最多支持添加10个");
        }

        for (ActiveEnrollInfoSonDto activeEnrollInfo : activeEnrollInfos) {
            // 类型(1-填写项，2-单选项，3-多选项)
            Integer type = activeEnrollInfo.getType();
            if (type == null || ActiveEnrollInfoTypeEnum.typeOf(type) == null) {
                Throw.isBusinessException("报名信息错误");
            }

            if (ActiveEnrollInfoTypeEnum.SINGLE.getValue().equals(type)) {
                List<ActiveEnrollInfoOptionDto> activeEnrollInfoOptions = activeEnrollInfo.getActiveEnrollInfoOptions();
                if (CollectionUtils.isEmpty(activeEnrollInfoOptions)) {
                    Throw.isBusinessException("报名信息错误");
                }

                if (activeEnrollInfoOptions.size() < 2) {
                    Throw.isBusinessException("报名信息单选项最少2个");
                }

                if (activeEnrollInfoOptions.size() > 10) {
                    Throw.isBusinessException("报名信息单选项最多10个");
                }
            }

            if (ActiveEnrollInfoTypeEnum.MULTIPLE.getValue().equals(type)) {
                List<ActiveEnrollInfoOptionDto> activeEnrollInfoOptions = activeEnrollInfo.getActiveEnrollInfoOptions();
                if (CollectionUtils.isEmpty(activeEnrollInfoOptions)) {
                    Throw.isBusinessException("报名信息错误");
                }

                if (activeEnrollInfoOptions.size() < 2) {
                    Throw.isBusinessException("报名信息多选项最少2个");
                }

                if (activeEnrollInfoOptions.size() > 10) {
                    Throw.isBusinessException("报名信息多选项最多10个");
                }
            }
        }
    }

}
